﻿using Microsoft.Practices.Prism.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;

namespace HobSoft.SoccerBet2014.Client.ViewModels
{
    using Common;
    using Domain.ClientService;
    using Domain.IRepositories;
    using dm = Domain.Models;
    using dmr = Domain.Models.BfRaw;

    public class OrderShellModel : CommandViewModel, IDisposable
    {
        #region public setting
        private double _orderRefreshTick;
        public double OrderRefreshTick
        {
            get {
                if (_orderRefreshTick <= 0)
                    _orderRefreshTick = Properties.Settings.Default.VM_OrderShellModel_RefreshOrder;
                return _orderRefreshTick; 
            }
            set { _orderRefreshTick = value; }
        }

        private double _bfOrderRefreshTick;
        public double BfOrderRefreshTick
        {
            get {
                if (_bfOrderRefreshTick <= 0)
                    _bfOrderRefreshTick = Properties.Settings.Default.VM_BFOrderShellModel_RefreshOrder;
                return _bfOrderRefreshTick; 
            }
            set { _bfOrderRefreshTick = value; }
        }
        #endregion

        #region command
        
        public ICommand QueryBmOrderCommand
        {
            get;
            protected set;
        }

        public ICommand QueryBfOrderCommand
        {
            get;
            protected set;
        }
        
        #endregion

        #region command imple
        public void QueryBmOrder()
        {
            bool hasLogin = false;
            foreach (var bm in Bookmakers)
            {
                Task<Task<bool>> checkTask = Task.Factory.StartNew(() => betSiteProxyService.HasLogin(bm.BmID));
                Task.WaitAll(checkTask);
                if (checkTask.Exception != null) continue;
                if (checkTask.Result.Result)
                {
                    hasLogin = true;
                    break;
                }
            }
            if (OnQueryOrder) return;
            if (hasLogin)
            {
                BmTimer.Stop();
                RaiseCommandStart(QueryBmOrderCommand, "查询订单");
                OnQueryOrder = true;
                var task = Task.Factory.StartNew(() => betSiteProxyService.RequestAllOrder());
                task.ContinueWith(t =>
                {
                    BetApplication.Current.Dispatcher.Invoke(() =>
                    {
                        RaiseCommandOver(QueryBmOrderCommand);
                        OnQueryOrder = false;
                        if (EnableBmTimer)
                            BmTimer.Start();
                        if (task.IsCanceled || task.Exception != null) return;
                        if (task.Result.Result == null || !task.Result.Result.Any()) return;
                        MappingOrderModels(task.Result.Result);
                    });
                });
            }
        }

        public void QueryBfOrder()
        {
            if (bfRequestService == null) return;
            if (CommandOnExecuting(QueryBfOrderCommand)) return;
            var checkLogin = bfRequestService.HasLogin();
            Task.WaitAll(checkLogin);
            if (checkLogin.Exception != null) return;
            if (!checkLogin.Result) return;
            BfTimer.Stop();
            RaiseCommandStart(QueryBfOrderCommand, "查询bf订单");
            bfRequestService.GetOrders().ContinueWith(t =>
            {
                BetApplication.Current.Dispatcher.Invoke(() =>
                {
                    if (EnableBfTimer)
                        BfTimer.Start();
                    RaiseCommandOver(QueryBfOrderCommand);
                    if (t.Exception != null)
                    {
                        RaiseCommandError(t.Exception.InnerException);
                    }
                    if (t.IsCompleted)
                    {
                        if (t.Result != null)
                        {
                            MappingBfOrderModels(t.Result);
                        }
                    }
                });
            });
        }
        #endregion

        #region cort & initialize
        protected bool EnableBmTimer { get; set; }
        protected bool EnableBfTimer { get; set; }
        protected DispatcherTimer BmTimer { get; set; }
        protected DispatcherTimer BfTimer { get; set; }
        protected IList<dm.Bookmaker> Bookmakers { get; set; }
        private readonly IBetSiteProxyService betSiteProxyService;
        private readonly IBookmakerRepository bmRepository;
        private readonly IBfRequestService bfRequestService;
        private readonly Factory.IViewModelFactory viewModelFactory;
        private readonly BetShellModel betShellModel;
        public OrderShellModel(IBetSiteProxyService _betSiteProxyService
                                            , IBfRequestService _bfRequestService
                                            , Factory.IViewModelFactory _viewModelFacotry
                                            , IBookmakerRepository _bmRepository)
        {
            betSiteProxyService = _betSiteProxyService;
            bfRequestService = _bfRequestService;
            viewModelFactory = _viewModelFacotry;
            bmRepository = _bmRepository;
            betShellModel = viewModelFactory.CreateOrGet<BetShellModel>();
            InitializeModels();
        }

        protected void InitializeModels()
        {
            QueryBmOrderCommand = new DelegateCommand(QueryBmOrder);
            QueryBfOrderCommand = new DelegateCommand(QueryBfOrder);
            RegisterCommand(QueryBmOrderCommand, "查询网站订单");
            RegisterCommand(QueryBfOrderCommand, "查询Bf订单");

            BetApplication.Current.Exit += BetApplication_Exit;
            Bookmakers = bmRepository.GetMany(b => true);

            BmOrderModels = new ObservableCollection<BmOrder>();
            BmOrderView = new ListCollectionView(BmOrderModels);
            BmOrderView.SortDescriptions.Add(new SortDescription("BetTime", ListSortDirection.Descending));
            WaitingBmOrderView = new ListCollectionView(BmOrderModels);
            WaitingBmOrderView.SortDescriptions.Add(new SortDescription("BetTime", ListSortDirection.Descending));
            WaitingBmOrderView.Filter = (o) => ((BmOrder)o).RawResult == "等待中";

            BfOrderModels = new ObservableCollection<BfOrder>();
            BfOrderView = new ListCollectionView(BfOrderModels);
            BfOrderView.Filter = o => ((BfOrder)o).OrderState == dmr.OrderStatus.EXECUTABLE;
            BfOrderView.SortDescriptions.Add(new SortDescription("SubmitTime", ListSortDirection.Descending));

            BfCompleteOrderView = new ListCollectionView(BfOrderModels);
            BfCompleteOrderView.Filter = o => ((BfOrder)o).OrderState == dmr.OrderStatus.EXECUTION_COMPLETE;
            BfCompleteOrderView.SortDescriptions.Add(new SortDescription("SubmitTime", ListSortDirection.Descending));

            EnableBmTimer = true;
            EnableBfTimer = true;
            BmTimer = new DispatcherTimer();
            BmTimer.Interval = TimeSpan.FromMilliseconds(OrderRefreshTick);
            BmTimer.Tick += BmTimer_Tick;
            BmTimer.Start();

            BfTimer = new DispatcherTimer();
            BfTimer.Interval = TimeSpan.FromMilliseconds(BfOrderRefreshTick);
            BfTimer.Tick += BfTimer_Tick;
            BfTimer.Start();
        }
        #endregion

        #region event handler
        private void BetApplication_Exit(object sender, System.Windows.ExitEventArgs e)
        {
            BmTimer.Stop();
            BfTimer.Stop();
        }

        private void BmTimer_Tick(object sender, EventArgs e)
        {
            QueryBmOrder();
        }

        private void BfTimer_Tick(object sender, EventArgs e)
        {
            QueryBfOrder();
        }

        private void BfOrder_OnCancelSucceed(object sender, string e)
        {
            QueryBfOrder();
        }
        #endregion

        #region local method
        protected void MappingBfOrderModels(dmr.CurrentOrderSummaryReport orderReport)
        {
            if (orderReport == null || orderReport.CurrentOrders == null) return;
            var version = DateTime.Now.Ticks;
            if (BfOrderView.Filter == null)
                BfOrderView.Filter = o => ((BfOrder)o).OrderState == dmr.OrderStatus.EXECUTABLE;
            if (BfCompleteOrderView.Filter == null)
                BfCompleteOrderView.Filter = o => ((BfOrder)o).OrderState == dmr.OrderStatus.EXECUTION_COMPLETE;
            foreach (var dmOrder in orderReport.CurrentOrders)
            {
                var vmOrder = BfOrderModels.FirstOrDefault(o => o.MarketID == dmOrder.MarketId && o.SelectionID == o.SelectionID && o.BetID == dmOrder.BetId);
                var bfEvent = betShellModel.BfEventModels.FirstOrDefault(be => be.MarketModels.Any(m => m.MarketID == dmOrder.MarketId));
                var market = bfEvent != null ? bfEvent.MarketModels.FirstOrDefault(m => m.MarketID == dmOrder.MarketId) : null;
                var runner = market != null ? market.Runners.FirstOrDefault(r => r.SelectionID == dmOrder.SelectionId) : null;
                if (vmOrder == null)
                {
                    vmOrder = viewModelFactory.CreateOrGet<BfOrder>();
                    vmOrder.OnCancelSucceed += BfOrder_OnCancelSucceed;
                    if (bfEvent != null)
                    {
                        vmOrder.HomeTeam = bfEvent.HomeTeam;
                        vmOrder.AwayTeam = bfEvent.AwayTeam;
                        vmOrder.RunnerName = runner != null ? runner.RunnerName : string.Empty;
                    }
                    BfOrderModels.Add(vmOrder);
                }
                AutoMapper.Mapper.Map(dmOrder, vmOrder);
                vmOrder.Version = version;
            }
            for (int i = 0; i < BfOrderModels.Count; i++)
            {
                if (BfOrderModels[i].Version != version)
                {
                    BfOrderModels[i].OnCancelSucceed -= BfOrder_OnCancelSucceed;
                    BfOrderModels.RemoveAt(i);
                }
            }
        }

        protected void MappingOrderModels(IList<dm.Site.BettingOrder> dmOrders)
        {
            foreach (var dmOrder in dmOrders)
            {
                var vmOrder = BmOrderModels.FirstOrDefault(o => o.BmID == dmOrder.BmID && o.RecID == dmOrder.RecID);
                if (vmOrder == null)
                {
                    vmOrder = viewModelFactory.CreateOrGet<BmOrder>();
                    BmOrderModels.Add(vmOrder);
                }
                AutoMapper.Mapper.Map(dmOrder, vmOrder);
            }

        }
        #endregion

        #region state property
        private bool _onQueryOrder;

        public bool OnQueryOrder
        {
            get { return _onQueryOrder; }
            protected set
            {
                PropertyValueChange(ref _onQueryOrder, value, "OnQueryOrder");
            }
        }
        #endregion

        #region model property
        private ObservableCollection<BfOrder> _bfOrderModels;

        public ObservableCollection<BfOrder> BfOrderModels
        {
            get { return _bfOrderModels; }
            protected set
            {
                PropertyValueChange(ref _bfOrderModels, value, "BfOrderModels");
            }
        }

        private ICollectionView _bfOrderModelsView;

        public ICollectionView BfOrderView
        {
            get { return _bfOrderModelsView; }
            protected set
            {
                PropertyValueChange(ref _bfOrderModelsView, value, "BfOrderView");
            }
        }

        private ICollectionView _bfCompleteOrderView;

        public ICollectionView BfCompleteOrderView
        {
            get { return _bfCompleteOrderView; }
            protected set
            {
                PropertyValueChange(ref _bfCompleteOrderView, value, "BfCompleteOrderView");
            }
        }

        private ObservableCollection<BmOrder> _bmOrderModels;

        public ObservableCollection<BmOrder> BmOrderModels
        {
            get { return _bmOrderModels; }
            protected set
            {
                PropertyValueChange(ref _bmOrderModels, value, "BmOrderModels");
            }
        }

        private ICollectionView _waitingBmOrderView;
        public ICollectionView WaitingBmOrderView
        {
            get { return _waitingBmOrderView; }
            protected set
            {
                PropertyValueChange(ref _waitingBmOrderView, value, "BmOrderModels");
            }
        }

        private ICollectionView _bmOrderView;

        public ICollectionView BmOrderView
        {
            get { return _bmOrderView; }
            protected set
            {
                PropertyValueChange(ref _bmOrderView, value, "BmOrderView");
            }
        }
        #endregion

        public void Dispose()
        {
            if (BmTimer != null)
            {
                BmTimer.Stop();
            }
        }
    }
}
